package com.wst.system.server.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wst.system.config.exception.GlobalExcetion;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.wst.system.server.entity.SysFileGroup;
import com.wst.system.server.entity.enm.SysFilePermission;
import com.wst.system.server.service.SysFileGroupService;
import com.wst.system.util.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wst.system.server.entity.SysFile;
import com.wst.system.server.mapper.SysFileMapper;
import com.wst.system.server.service.SysFileService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.BeanUtils;
import com.wst.system.server.entity.vo.SysFileVo;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.net.URLEncoder;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import com.wst.system.server.entity.vo.PageSearchVo;
import org.springframework.web.multipart.MultipartFile;

import javax.crypto.SecretKey;

/**
 * <p>
 * 文件表 服务实现类
 * </p>
 *
 * @author X.I.O
 * @since 2025-02-27
 */
@Service
@Transactional
public class SysFileServiceImpl extends ServiceImpl<SysFileMapper, SysFile> implements SysFileService {

    @Value("${upload.dir}")
    private String uploadDir;

    @Value("${upload.privateKey}")
    private String privateKey;

    @Autowired
    private SysFileGroupService sysFileGroupService;

    @Override
    public SysFile getById(Serializable id){
        return super.getById(id);
    }


    @Override
    public boolean removeById(Serializable id) {
        return super.removeById(id);
    }


    @Override
    public boolean updateById(SysFile sysfile) {
        return super.updateById(sysfile);
    }


    public SysFile saveSysFile(SysFile sysfile) throws GlobalExcetion {
        super.save(sysfile);
        return sysfile;
    }


    public SysFile updateSysFileById(SysFile sysfile) throws GlobalExcetion{
        super.updateById(sysfile);
        return sysfile;
    }


    public SysFile saveOrUpdateSysFile(SysFileVo sysfileVo) throws GlobalExcetion{
        SysFile sysfile=new SysFile();
        BeanUtils.copyProperties(sysfileVo,sysfile);
        if(sysfileVo.getId()!=null){
            SysFile sysfileEntity=super.baseMapper.selectById(sysfileVo.getId());
            if(sysfileEntity==null){
                throw new GlobalExcetion(1,"数据不存在");
            }
            super.baseMapper.updateById(sysfile);
        }else{
            super.baseMapper.insert(sysfile);
        }
        return sysfile;
    }





    public IPage<SysFile> page(PageSearchVo vo) throws GlobalExcetion{
        Integer userId=SecurityUtil.getUserId();
        LambdaQueryWrapper<SysFile> lambdaQueryWrapper=new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(SysFile::getFileUid, userId);
        if(JSONUtil.isNotBlank(vo.getSearch(),"fileName")){
            lambdaQueryWrapper.like(SysFile::getFileName,vo.getString("fileName"));
        }
        if(JSONUtil.isNotBlank(vo.getSearch(),"filePermission")){
            lambdaQueryWrapper.eq(SysFile::getFilePermission,vo.getString("filePermission"));
        }
        if(JSONUtil.isNotBlank(vo.getSearch(),"fileType")){
            lambdaQueryWrapper.like(SysFile::getFileType,vo.getString("fileType"));
        }
        if(JSONUtil.isNotBlank(vo.getSearch(),"groupId")){
            List<Integer> ids=sysFileGroupService.getChildIdsByParentId(vo.getString("groupId"));
            if(ids.size()>0){
                lambdaQueryWrapper.in(SysFile::getGroupId,ids);
            }else {
                lambdaQueryWrapper.eq(SysFile::getGroupId,vo.getString("groupId"));
            }
        }
        lambdaQueryWrapper.orderByDesc(SysFile::getCreateTime);
        IPage<SysFile> iPage=super.baseMapper.selectPage(new Page(vo.getPageNum(), vo.getPageSize()),lambdaQueryWrapper);
        if(iPage.getRecords()!=null && !iPage.getRecords().isEmpty()){
            List<String> groupIds=iPage.getRecords().stream().map(SysFile::getGroupId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            List<SysFileGroup> sysFileGroupList;
            if(!groupIds.isEmpty()){
                sysFileGroupList=sysFileGroupService.listByIds(groupIds);
            } else {
                sysFileGroupList = new ArrayList<>();
            }
            iPage.getRecords().forEach((e)->{
                if(e.getGroupId()!=null ){
                    SysFileGroup sysFileGroup=sysFileGroupList.stream().filter((f)->String.valueOf(e.getGroupId()).equals(String.valueOf(f.getId()))).findFirst().orElse(null);
                    if(sysFileGroup!=null){
                        e.setGroupName(sysFileGroup.getGroupName());
                    }else {
                        e.setGroupName("未分组");
                    }
                }else {
                    e.setGroupName("未分组");
                }
            });
        }
        return iPage;
    }

    @Override
    public SysFile uploadFile(MultipartFile file) throws Exception {
        String sha256= FileHashUtil.calculateSHA256(file.getBytes());
        String md5=FileHashUtil.calculateMD5(file.getBytes());
        SysFile sysFile=this.getSysFileByMd5andSha256(md5,sha256);
        SysFile targetSysFile=new SysFile();
        String str=new SimpleDateFormat("yyyy-MM").format(new Date());
        if(sysFile==null){
            String fileType=FileUtils.getFileType(file.getOriginalFilename());
            File encryptedFile=new File(uploadDir+File.separator+str+File.separator+ UUID.randomUUID().toString().replaceAll("-","")+"."+fileType);
            int passwordNum=RandomNumber.generateRandomNumber(6);
            AESFileUtil fileDESUtil = new AESFileUtil(String.valueOf(passwordNum));
            byte[] encryptByte=fileDESUtil.encrypt(file.getBytes());
            //存储文件
            FileUtils.outFileByPath(encryptByte,encryptedFile.getPath());
            targetSysFile.setFileSize(String.valueOf(file.getSize()));
            targetSysFile.setFileMd5(md5);
            targetSysFile.setFileSha256(sha256);
            targetSysFile.setFileName(file.getOriginalFilename());
            targetSysFile.setFileType(fileType);
            targetSysFile.setFilePath(encryptedFile.getPath());
            targetSysFile.setCode(String.valueOf(passwordNum));
            targetSysFile.setIsEncrypt(1);
        }else {
            BeanUtils.copyProperties(sysFile,targetSysFile);
        }
        targetSysFile.setFilePermission(SysFilePermission.PUBLIC.getPermissionCode().toString());
        targetSysFile.setUploadTime(new Date());
        this.baseMapper.insert(targetSysFile);
        return targetSysFile;
    }

    @Override
    public SysFile uploadFile(MultipartFile file,String groupId) throws Exception {
        SysFileGroup sysFileGroup=sysFileGroupService.getById(groupId);
        if(sysFileGroup==null){
            throw new GlobalExcetion(1,"文件分组不得为空");
        }
        Integer userId= SecurityUtil.getUserId();
        String sha256= FileHashUtil.calculateSHA256(file.getBytes());
        String md5=FileHashUtil.calculateMD5(file.getBytes());
        SysFile sysFile=this.getSysFileByMd5andSha256(md5,sha256);
        SysFile targetSysFile=new SysFile();
        String str=new SimpleDateFormat("yyyy-MM").format(new Date());
        if(sysFile==null){
            String fileType=FileUtils.getFileType(file.getOriginalFilename());
            File encryptedFile=new File(uploadDir+File.separator+str+File.separator+ UUID.randomUUID().toString().replaceAll("-","")+"."+fileType);
            int passwordNum=RandomNumber.generateRandomNumber(6);
            AESFileUtil fileDESUtil = new AESFileUtil(String.valueOf(passwordNum));
            byte[] encryptByte=fileDESUtil.encrypt(file.getBytes());
            //存储文件
            FileUtils.outFileByPath(encryptByte,encryptedFile.getPath());
            targetSysFile.setFileSize(String.valueOf(file.getSize()));
            targetSysFile.setFileMd5(md5);
            targetSysFile.setFileSha256(sha256);
            targetSysFile.setFileName(file.getOriginalFilename());
            targetSysFile.setFileType(fileType);
            targetSysFile.setFilePath(encryptedFile.getPath());
            targetSysFile.setCode(String.valueOf(passwordNum));
            targetSysFile.setIsEncrypt(1);
            targetSysFile.setFilePermission(SysFilePermission.PRIVATE.getPermissionCode().toString());
        }else {
            BeanUtils.copyProperties(sysFile,targetSysFile);
        }
        targetSysFile.setGroupId(groupId);
        targetSysFile.setUploadTime(new Date());
        targetSysFile.setFileUid(userId.toString());
        this.baseMapper.insert(targetSysFile);
        return targetSysFile;
    }

    @Override
    public SysFile uploadFile(MultipartFile file,String groupId, String tableName, String tableField, String bindId) throws Exception {
        SysFile sysFile=uploadFile(file,groupId);
        sysFile.setTableName(tableName);
        sysFile.setTableFieldid(tableField);
        sysFile.setBindId(bindId);
        this.baseMapper.updateById(sysFile);
        return sysFile;
    }

    @Override
    public SysFile getSysFileByMd5andSha256(String md5, String sha256) throws GlobalExcetion {
        LambdaQueryWrapper<SysFile> lambdaQueryWrapper=new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(SysFile::getFileMd5,md5);
        lambdaQueryWrapper.eq(SysFile::getFileSha256,sha256);
        List<SysFile> sysFileList= this.baseMapper.selectList(lambdaQueryWrapper);
        if(sysFileList==null || sysFileList.isEmpty()){
            return null;
        }
        return sysFileList.get(sysFileList.size()-1);
    }

    @Override
    public String getSysFileUrl(SysFile sysFile,Long expireTime) throws GlobalExcetion {
        JSONObject jsonObject=new JSONObject();
        if(expireTime==null){
            jsonObject.put("expire_time",0);
        }else {
            jsonObject.put("expire_time",expireTime);
        }
        jsonObject.put("id",sysFile.getId());
        SecretKey publicKey=TextEncryptUtils.generateAesKey();
        String pk=TextEncryptUtils.keyToString(publicKey);
        String es=TextEncryptUtils.encryptText(jsonObject,publicKey,privateKey);
        String url="/sys-file/res/donload?pk="+ URLEncoder.encode(pk)+"&es="+ URLEncoder.encode(es);
        return url;
    }

    @Override
    public int updateBatchPermession(List<String> ids, String permession, String uid) throws GlobalExcetion {
        return this.baseMapper.updateBatchPermession(ids,permession,uid);
    }

    @Override
    public int removeBySha256Md5(String sha256, String md5) throws GlobalExcetion {
        LambdaQueryWrapper<SysFile> sysFileLambdaQueryWrapper=new LambdaQueryWrapper<>();
        sysFileLambdaQueryWrapper.eq(SysFile::getFileSha256,sha256);
        sysFileLambdaQueryWrapper.eq(SysFile::getFileMd5,md5);
        sysFileLambdaQueryWrapper.eq(SysFile::getFilePermission,SysFilePermission.PUBLIC.getPermissionCode().toString());
        return this.baseMapper.delete(sysFileLambdaQueryWrapper);
    }
}